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
|
|
|
|
2023-05-02 14:12:22 +00:00
|
|
|
use std::mem;
|
2020-07-31 17:54:16 +00:00
|
|
|
|
2023-03-08 17:28:52 +00:00
|
|
|
use base_db::CrateId;
|
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-03-14 06:25:30 +00:00
|
|
|
name::{name, AsName, Name},
|
2023-04-07 07:34:04 +00:00
|
|
|
AstId, ExpandError, 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;
|
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::{
|
2023-04-28 17:14:30 +00:00
|
|
|
self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName,
|
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
|
|
|
};
|
2023-05-02 14:12:22 +00:00
|
|
|
use triomphe::Arc;
|
2019-11-12 12:09:25 +00:00
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
use crate::{
|
2023-04-17 15:31:39 +00:00
|
|
|
body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
|
2023-04-06 17:23:29 +00:00
|
|
|
data::adt::StructKind,
|
2019-11-23 11:44:43 +00:00
|
|
|
db::DefDatabase,
|
2023-04-17 15:31:39 +00:00
|
|
|
expander::Expander,
|
2023-04-06 17:36:25 +00:00
|
|
|
hir::{
|
2023-04-06 12:44:38 +00:00
|
|
|
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr,
|
|
|
|
ExprId, 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,
|
2023-03-08 17:28:52 +00:00
|
|
|
lang_item::LangItem,
|
2023-04-17 15:31:39 +00:00
|
|
|
lower::LowerCtx,
|
2023-05-11 06:52:13 +00:00
|
|
|
nameres::{DefMap, MacroSubNs},
|
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-05-12 14:47:15 +00:00
|
|
|
AdtId, BlockId, BlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
pub(super) fn lower(
|
2020-03-13 15:05:46 +00:00
|
|
|
db: &dyn DefDatabase,
|
2023-05-12 14:47:15 +00:00
|
|
|
owner: DefWithBodyId,
|
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>,
|
2023-03-08 17:28:52 +00:00
|
|
|
krate: CrateId,
|
2023-04-04 19:37:38 +00:00
|
|
|
is_async_fn: bool,
|
2019-11-12 15:46:57 +00:00
|
|
|
) -> (Body, BodySourceMap) {
|
|
|
|
ExprCollector {
|
|
|
|
db,
|
2023-05-12 14:47:15 +00:00
|
|
|
owner,
|
2023-03-08 17:28:52 +00:00
|
|
|
krate,
|
2023-05-04 18:46:05 +00:00
|
|
|
def_map: expander.module.def_map(db),
|
2019-11-12 15:46:57 +00:00
|
|
|
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(),
|
2019-11-12 15:46:57 +00:00
|
|
|
},
|
2020-06-24 14:21:00 +00:00
|
|
|
expander,
|
2023-04-06 10:50:16 +00:00
|
|
|
current_try_block_label: None,
|
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,
|
2023-04-06 10:50:16 +00:00
|
|
|
label_ribs: Vec::new(),
|
2023-04-06 12:44:38 +00:00
|
|
|
current_binding_owner: None,
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2023-04-04 19:37:38 +00:00
|
|
|
.collect(params, body, is_async_fn)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
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,
|
2023-05-12 14:47:15 +00:00
|
|
|
owner: DefWithBodyId,
|
2023-04-17 15:31:39 +00:00
|
|
|
def_map: Arc<DefMap>,
|
2022-07-21 00:00:58 +00:00
|
|
|
ast_id_map: Arc<AstIdMap>,
|
2023-03-08 17:28:52 +00:00
|
|
|
krate: CrateId,
|
2023-04-07 07:34:04 +00:00
|
|
|
body: Body,
|
2019-11-12 15:46:57 +00:00
|
|
|
source_map: BodySourceMap,
|
2023-04-07 07:34:04 +00:00
|
|
|
|
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,
|
2023-04-07 07:34:04 +00:00
|
|
|
|
|
|
|
current_try_block_label: Option<LabelId>,
|
|
|
|
// points to the expression that a try expression will target (replaces current_try_block_label)
|
|
|
|
// catch_scope: Option<ExprId>,
|
|
|
|
// points to the expression that an unlabeled control flow will target
|
|
|
|
// loop_scope: Option<ExprId>,
|
|
|
|
// needed to diagnose non label control flow in while conditions
|
|
|
|
// is_in_loop_condition: bool,
|
|
|
|
|
|
|
|
// resolution
|
2023-04-06 10:50:16 +00:00
|
|
|
label_ribs: Vec<LabelRib>,
|
2023-04-06 12:44:38 +00:00
|
|
|
current_binding_owner: Option<ExprId>,
|
2023-04-06 10:50:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct LabelRib {
|
|
|
|
kind: RibKind,
|
|
|
|
// Once we handle macro hygiene this will need to be a map
|
|
|
|
label: Option<(Name, LabelId)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LabelRib {
|
|
|
|
fn new(kind: RibKind) -> Self {
|
|
|
|
LabelRib { kind, label: None }
|
|
|
|
}
|
|
|
|
fn new_normal(label: (Name, LabelId)) -> Self {
|
|
|
|
LabelRib { kind: RibKind::Normal, label: Some(label) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
enum RibKind {
|
|
|
|
Normal,
|
|
|
|
Closure,
|
|
|
|
Constant,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RibKind {
|
|
|
|
/// This rib forbids referring to labels defined in upwards ribs.
|
|
|
|
fn is_label_barrier(self) -> bool {
|
|
|
|
match self {
|
|
|
|
RibKind::Normal => false,
|
|
|
|
RibKind::Closure | RibKind::Constant => true,
|
|
|
|
}
|
|
|
|
}
|
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>,
|
2023-04-04 19:37:38 +00:00
|
|
|
is_async_fn: bool,
|
2019-11-12 15:46:57 +00:00
|
|
|
) -> (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);
|
|
|
|
}
|
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled)
|
2022-10-10 07:47:09 +00:00
|
|
|
{
|
2023-04-07 07:34:04 +00:00
|
|
|
let param_pat = self.collect_pat_top(param.pat());
|
2019-11-12 15:46:57 +00:00
|
|
|
self.body.params.push(param_pat);
|
|
|
|
}
|
|
|
|
};
|
2023-04-06 10:50:16 +00:00
|
|
|
self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| {
|
|
|
|
if is_async_fn {
|
|
|
|
match body {
|
|
|
|
Some(e) => {
|
|
|
|
let expr = this.collect_expr(e);
|
|
|
|
this.alloc_expr_desugared(Expr::Async {
|
|
|
|
id: None,
|
|
|
|
statements: Box::new([]),
|
|
|
|
tail: Some(expr),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
None => this.missing_expr(),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.collect_expr_opt(body)
|
|
|
|
}
|
|
|
|
});
|
2019-11-12 15:46:57 +00:00
|
|
|
|
|
|
|
(self.body, self.source_map)
|
|
|
|
}
|
|
|
|
|
2021-05-06 17:59:54 +00:00
|
|
|
fn ctx(&self) -> LowerCtx<'_> {
|
2023-04-06 19:16:11 +00:00
|
|
|
self.expander.ctx(self.db)
|
2020-05-17 15:37:30 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2023-04-06 10:50:16 +00:00
|
|
|
// FIXME: Move some of these arms out into separate methods for clarity
|
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) => {
|
2023-04-07 07:34:04 +00:00
|
|
|
let pat = self.collect_pat_top(e.pat());
|
2022-01-23 03:39:26 +00:00
|
|
|
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() {
|
2023-04-06 10:50:16 +00:00
|
|
|
Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e),
|
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-04-06 10:50:16 +00:00
|
|
|
self.with_labeled_rib(label, |this| {
|
|
|
|
this.collect_block_(e, |id, statements, tail| Expr::Block {
|
|
|
|
id,
|
|
|
|
statements,
|
|
|
|
tail,
|
|
|
|
label: Some(label),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Some(ast::BlockModifier::Async(_)) => {
|
|
|
|
self.with_label_rib(RibKind::Closure, |this| {
|
|
|
|
this.collect_block_(e, |id, statements, tail| Expr::Async {
|
|
|
|
id,
|
|
|
|
statements,
|
|
|
|
tail,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Some(ast::BlockModifier::Const(_)) => {
|
|
|
|
self.with_label_rib(RibKind::Constant, |this| {
|
2023-05-12 14:47:15 +00:00
|
|
|
let (result_expr_id, prev_binding_owner) =
|
|
|
|
this.initialize_binding_owner(syntax_ptr);
|
|
|
|
let inner_expr = this.collect_block(e);
|
|
|
|
let x = this.db.intern_anonymous_const((this.owner, inner_expr));
|
|
|
|
this.body.exprs[result_expr_id] = Expr::Const(x);
|
|
|
|
this.current_binding_owner = prev_binding_owner;
|
|
|
|
result_expr_id
|
2023-03-04 13:45:57 +00:00
|
|
|
})
|
2020-12-23 11:24:24 +00:00
|
|
|
}
|
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));
|
2023-04-06 10:50:16 +00:00
|
|
|
let body = self.collect_labelled_block_opt(label, 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));
|
2023-04-06 10:50:16 +00:00
|
|
|
let body = self.collect_labelled_block_opt(label, 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());
|
2023-04-07 07:34:04 +00:00
|
|
|
let pat = self.collect_pat_top(e.pat());
|
2023-04-06 10:50:16 +00:00
|
|
|
let body = self.collect_labelled_block_opt(label, 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) => {
|
2023-04-28 17:14:30 +00:00
|
|
|
let is_rustc_box = {
|
|
|
|
let attrs = e.attrs();
|
|
|
|
attrs.filter_map(|x| x.as_simple_atom()).any(|x| x == "rustc_box")
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
2023-04-28 17:14:30 +00:00
|
|
|
if is_rustc_box {
|
|
|
|
let expr = self.collect_expr_opt(e.arg_list().and_then(|x| x.args().next()));
|
|
|
|
self.alloc_expr(Expr::Box { expr }, syntax_ptr)
|
|
|
|
} else {
|
|
|
|
let callee = self.collect_expr_opt(e.expr());
|
|
|
|
let args = if let Some(arg_list) = e.arg_list() {
|
|
|
|
arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
|
|
|
|
} else {
|
|
|
|
Box::default()
|
|
|
|
};
|
|
|
|
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 {
|
2023-04-07 07:34:04 +00:00
|
|
|
pat: self.collect_pat_top(arm.pat()),
|
2020-10-23 17:27:04 +00:00
|
|
|
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
|
|
|
}
|
2023-04-06 10:50:16 +00:00
|
|
|
ast::Expr::ContinueExpr(e) => {
|
|
|
|
let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
|
|
|
|
self.source_map.diagnostics.push(e);
|
|
|
|
None
|
|
|
|
});
|
|
|
|
self.alloc_expr(Expr::Continue { label }, syntax_ptr)
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::BreakExpr(e) => {
|
2023-04-06 10:50:16 +00:00
|
|
|
let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
|
|
|
|
self.source_map.diagnostics.push(e);
|
|
|
|
None
|
|
|
|
});
|
2019-11-12 15:46:57 +00:00
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
2023-04-06 10:50:16 +00:00
|
|
|
self.alloc_expr(Expr::Break { expr, label }, syntax_ptr)
|
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
|
|
|
}
|
2023-03-08 17:28:52 +00:00
|
|
|
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
|
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
|
|
|
}
|
|
|
|
}
|
2023-04-06 10:50:16 +00:00
|
|
|
ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
|
2023-04-06 12:44:38 +00:00
|
|
|
let (result_expr_id, prev_binding_owner) =
|
|
|
|
this.initialize_binding_owner(syntax_ptr);
|
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() {
|
2023-04-07 07:34:04 +00:00
|
|
|
let pat = this.collect_pat_top(param.pat());
|
2021-04-06 14:07:45 +00:00
|
|
|
let type_ref =
|
2023-04-06 10:50:16 +00:00
|
|
|
param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.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())
|
2023-04-06 10:50:16 +00:00
|
|
|
.map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
|
2022-09-05 13:43:26 +00:00
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
let prev_is_lowering_generator = mem::take(&mut this.is_lowering_generator);
|
2023-05-01 22:58:14 +00:00
|
|
|
let prev_try_block_label = this.current_try_block_label.take();
|
2022-09-05 13:43:26 +00:00
|
|
|
|
2023-04-06 10:50:16 +00:00
|
|
|
let body = this.collect_expr_opt(e.body());
|
2022-09-05 13:43:26 +00:00
|
|
|
|
2023-04-06 10:50:16 +00:00
|
|
|
let closure_kind = if this.is_lowering_generator {
|
2022-09-05 13:43:26 +00:00
|
|
|
let movability = if e.static_token().is_some() {
|
|
|
|
Movability::Static
|
|
|
|
} else {
|
|
|
|
Movability::Movable
|
|
|
|
};
|
|
|
|
ClosureKind::Generator(movability)
|
2022-08-07 02:11:02 +00:00
|
|
|
} else if e.async_token().is_some() {
|
|
|
|
ClosureKind::Async
|
2022-09-05 13:43:26 +00:00
|
|
|
} else {
|
|
|
|
ClosureKind::Closure
|
|
|
|
};
|
2023-04-06 12:44:38 +00:00
|
|
|
let capture_by =
|
|
|
|
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
|
|
|
|
this.is_lowering_generator = prev_is_lowering_generator;
|
|
|
|
this.current_binding_owner = prev_binding_owner;
|
2023-05-01 22:58:14 +00:00
|
|
|
this.current_try_block_label = prev_try_block_label;
|
2023-04-06 12:44:38 +00:00
|
|
|
this.body.exprs[result_expr_id] = Expr::Closure {
|
|
|
|
args: args.into(),
|
|
|
|
arg_types: arg_types.into(),
|
|
|
|
ret_type,
|
|
|
|
body,
|
|
|
|
closure_kind,
|
|
|
|
capture_by,
|
|
|
|
};
|
|
|
|
result_expr_id
|
2023-04-06 10:50:16 +00:00
|
|
|
}),
|
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);
|
2023-04-06 10:50:16 +00:00
|
|
|
let repeat = self.with_label_rib(RibKind::Constant, |this| {
|
2023-04-06 12:44:38 +00:00
|
|
|
if let Some(repeat) = repeat {
|
|
|
|
let syntax_ptr = AstPtr::new(&repeat);
|
|
|
|
this.collect_as_a_binding_owner_bad(
|
|
|
|
|this| this.collect_expr(repeat),
|
|
|
|
syntax_ptr,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
this.missing_expr()
|
|
|
|
}
|
2023-04-06 10:50:16 +00:00
|
|
|
});
|
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
|
|
|
|
2023-04-06 12:44:38 +00:00
|
|
|
fn initialize_binding_owner(
|
|
|
|
&mut self,
|
|
|
|
syntax_ptr: AstPtr<ast::Expr>,
|
|
|
|
) -> (ExprId, Option<ExprId>) {
|
|
|
|
let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
|
|
|
|
let prev_binding_owner = self.current_binding_owner.take();
|
|
|
|
self.current_binding_owner = Some(result_expr_id);
|
|
|
|
(result_expr_id, prev_binding_owner)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently
|
|
|
|
/// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have
|
|
|
|
/// their own body. Don't add more usage for this function so that we can remove this function after
|
|
|
|
/// separating those bodies.
|
|
|
|
fn collect_as_a_binding_owner_bad(
|
|
|
|
&mut self,
|
|
|
|
job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId,
|
|
|
|
syntax_ptr: AstPtr<ast::Expr>,
|
|
|
|
) -> ExprId {
|
|
|
|
let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr);
|
|
|
|
let tmp = job(self);
|
|
|
|
self.body.exprs[id] = mem::replace(&mut self.body.exprs[tmp], Expr::Missing);
|
|
|
|
self.current_binding_owner = prev_owner;
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2023-03-19 09:32:51 +00:00
|
|
|
/// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
|
|
|
|
/// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
|
|
|
|
/// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
|
2023-04-06 10:50:16 +00:00
|
|
|
fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
|
2023-03-19 09:32:51 +00:00
|
|
|
let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else {
|
2023-04-06 10:50:16 +00:00
|
|
|
return self.collect_block(e);
|
2023-03-19 09:32:51 +00:00
|
|
|
};
|
2023-04-06 10:50:16 +00:00
|
|
|
let label = self.alloc_label_desugared(Label { name: Name::generate_new_name() });
|
|
|
|
let old_label = self.current_try_block_label.replace(label);
|
|
|
|
|
|
|
|
let (btail, expr_id) = self.with_labeled_rib(label, |this| {
|
|
|
|
let mut btail = None;
|
|
|
|
let block = this.collect_block_(e, |id, statements, tail| {
|
|
|
|
btail = tail;
|
|
|
|
Expr::Block { id, statements, tail, label: Some(label) }
|
|
|
|
});
|
|
|
|
(btail, block)
|
|
|
|
});
|
|
|
|
|
2023-03-19 09:32:51 +00:00
|
|
|
let callee = self.alloc_expr_desugared(Expr::Path(try_from_output));
|
2023-04-06 10:50:16 +00:00
|
|
|
let next_tail = match btail {
|
2023-03-19 09:32:51 +00:00
|
|
|
Some(tail) => self.alloc_expr_desugared(Expr::Call {
|
|
|
|
callee,
|
|
|
|
args: Box::new([tail]),
|
|
|
|
is_assignee_expr: false,
|
|
|
|
}),
|
|
|
|
None => {
|
|
|
|
let unit = self.alloc_expr_desugared(Expr::Tuple {
|
|
|
|
exprs: Box::new([]),
|
|
|
|
is_assignee_expr: false,
|
|
|
|
});
|
|
|
|
self.alloc_expr_desugared(Expr::Call {
|
|
|
|
callee,
|
|
|
|
args: Box::new([unit]),
|
|
|
|
is_assignee_expr: false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else {
|
2023-04-06 10:50:16 +00:00
|
|
|
unreachable!("block was lowered to non-block");
|
2023-03-19 09:32:51 +00:00
|
|
|
};
|
|
|
|
*tail = Some(next_tail);
|
2023-04-06 10:50:16 +00:00
|
|
|
self.current_try_block_label = old_label;
|
2023-03-19 09:32:51 +00:00
|
|
|
expr_id
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Desugar `ast::TryExpr` from: `<expr>?` into:
|
|
|
|
/// ```ignore (pseudo-rust)
|
|
|
|
/// match Try::branch(<expr>) {
|
|
|
|
/// ControlFlow::Continue(val) => val,
|
|
|
|
/// ControlFlow::Break(residual) =>
|
|
|
|
/// // If there is an enclosing `try {...}`:
|
|
|
|
/// break 'catch_target Try::from_residual(residual),
|
|
|
|
/// // Otherwise:
|
|
|
|
/// return Try::from_residual(residual),
|
|
|
|
/// }
|
|
|
|
/// ```
|
2023-03-08 17:28:52 +00:00
|
|
|
fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId {
|
|
|
|
let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: {
|
|
|
|
if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) {
|
2023-03-17 10:32:55 +00:00
|
|
|
if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) {
|
|
|
|
if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) {
|
2023-03-08 17:28:52 +00:00
|
|
|
if let Some(try_from_residual) =
|
|
|
|
LangItem::TryTraitFromResidual.path(self.db, self.krate)
|
|
|
|
{
|
2023-03-17 10:32:55 +00:00
|
|
|
break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual);
|
2023-03-08 17:28:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Some of the needed lang items are missing, so we can't desugar
|
|
|
|
return self.alloc_expr(Expr::Missing, syntax_ptr);
|
|
|
|
};
|
|
|
|
let operand = self.collect_expr_opt(e.expr());
|
|
|
|
let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone());
|
|
|
|
let expr = self.alloc_expr(
|
2023-03-17 10:32:55 +00:00
|
|
|
Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
|
2023-03-08 17:28:52 +00:00
|
|
|
syntax_ptr.clone(),
|
|
|
|
);
|
2023-03-19 09:32:51 +00:00
|
|
|
let continue_name = Name::generate_new_name();
|
|
|
|
let continue_binding =
|
|
|
|
self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
|
2023-03-08 17:28:52 +00:00
|
|
|
let continue_bpat =
|
|
|
|
self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None });
|
|
|
|
self.add_definition_to_binding(continue_binding, continue_bpat);
|
|
|
|
let continue_arm = MatchArm {
|
|
|
|
pat: self.alloc_pat_desugared(Pat::TupleStruct {
|
|
|
|
path: Some(Box::new(cf_continue)),
|
|
|
|
args: Box::new([continue_bpat]),
|
|
|
|
ellipsis: None,
|
|
|
|
}),
|
|
|
|
guard: None,
|
2023-03-19 09:32:51 +00:00
|
|
|
expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr.clone()),
|
2023-03-08 17:28:52 +00:00
|
|
|
};
|
2023-03-19 09:32:51 +00:00
|
|
|
let break_name = Name::generate_new_name();
|
|
|
|
let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated);
|
2023-03-17 10:32:55 +00:00
|
|
|
let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
|
2023-03-08 17:28:52 +00:00
|
|
|
self.add_definition_to_binding(break_binding, break_bpat);
|
|
|
|
let break_arm = MatchArm {
|
|
|
|
pat: self.alloc_pat_desugared(Pat::TupleStruct {
|
|
|
|
path: Some(Box::new(cf_break)),
|
|
|
|
args: Box::new([break_bpat]),
|
|
|
|
ellipsis: None,
|
|
|
|
}),
|
|
|
|
guard: None,
|
|
|
|
expr: {
|
2023-03-19 09:32:51 +00:00
|
|
|
let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone());
|
2023-03-17 10:32:55 +00:00
|
|
|
let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone());
|
2023-03-08 17:28:52 +00:00
|
|
|
let result = self.alloc_expr(
|
|
|
|
Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false },
|
|
|
|
syntax_ptr.clone(),
|
|
|
|
);
|
2023-04-06 10:50:16 +00:00
|
|
|
self.alloc_expr(
|
|
|
|
match self.current_try_block_label {
|
|
|
|
Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
|
|
|
|
None => Expr::Return { expr: Some(result) },
|
|
|
|
},
|
|
|
|
syntax_ptr.clone(),
|
|
|
|
)
|
2023-03-08 17:28:52 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
let arms = Box::new([continue_arm, break_arm]);
|
|
|
|
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
|
|
|
|
}
|
|
|
|
|
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));
|
2023-04-17 15:31:39 +00:00
|
|
|
let module = self.expander.module.local_id;
|
|
|
|
let res = self.expander.enter_expand(self.db, mcall, |path| {
|
|
|
|
self.def_map
|
2023-05-11 06:52:13 +00:00
|
|
|
.resolve_path(
|
|
|
|
self.db,
|
|
|
|
module,
|
|
|
|
&path,
|
|
|
|
crate::item_scope::BuiltinShadowMode::Other,
|
|
|
|
Some(MacroSubNs::Bang),
|
|
|
|
)
|
2023-04-17 15:31:39 +00:00
|
|
|
.0
|
|
|
|
.take_macros()
|
|
|
|
});
|
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-04-07 07:34:04 +00:00
|
|
|
Some(ExpandError::RecursionOverflowPoisoned) => {
|
2023-02-08 11:11:54 +00:00
|
|
|
// 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
|
|
|
|
2023-04-16 15:22:06 +00:00
|
|
|
if record_diagnostics {
|
|
|
|
// FIXME: Report parse errors here
|
|
|
|
}
|
|
|
|
|
|
|
|
let id = collector(self, Some(expansion.tree()));
|
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
|
|
|
}
|
2023-04-07 07:34:04 +00:00
|
|
|
let pat = self.collect_pat_top(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,
|
2023-03-25 19:44:12 +00:00
|
|
|
mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
|
2023-03-04 13:45:57 +00:00
|
|
|
) -> ExprId {
|
2023-04-06 19:16:11 +00:00
|
|
|
let block_has_items = {
|
|
|
|
let statement_has_item = block.statements().any(|stmt| match stmt {
|
|
|
|
ast::Stmt::Item(_) => true,
|
|
|
|
// Macro calls can be both items and expressions. The syntax library always treats
|
|
|
|
// them as expressions here, so we undo that.
|
|
|
|
ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
|
|
|
|
_ => false,
|
|
|
|
});
|
|
|
|
statement_has_item || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
|
|
|
|
};
|
|
|
|
|
|
|
|
let block_id = if block_has_items {
|
2023-04-06 18:19:59 +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);
|
2023-04-17 15:31:39 +00:00
|
|
|
Some(self.db.intern_block(BlockLoc { ast_id, module: self.expander.module }))
|
2023-03-25 19:44:12 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2023-04-14 10:15:48 +00:00
|
|
|
let (module, def_map) =
|
|
|
|
match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
|
|
|
|
Some((def_map, block_id)) => {
|
|
|
|
self.body.block_scopes.push(block_id);
|
2023-04-17 15:31:39 +00:00
|
|
|
(def_map.module_id(def_map.root()), def_map)
|
2023-04-14 10:15:48 +00:00
|
|
|
}
|
2023-04-17 15:31:39 +00:00
|
|
|
None => (self.expander.module, self.def_map.clone()),
|
2023-04-14 10:15:48 +00:00
|
|
|
};
|
2023-04-17 15:31:39 +00:00
|
|
|
let prev_def_map = mem::replace(&mut self.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
|
|
|
|
2023-04-17 15:31:39 +00:00
|
|
|
self.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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-06 10:50:16 +00:00
|
|
|
fn collect_labelled_block_opt(
|
|
|
|
&mut self,
|
|
|
|
label: Option<LabelId>,
|
|
|
|
expr: Option<ast::BlockExpr>,
|
|
|
|
) -> ExprId {
|
|
|
|
match label {
|
|
|
|
Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)),
|
|
|
|
None => self.collect_block_opt(expr),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
// region: patterns
|
2022-03-04 18:49:08 +00:00
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
fn collect_pat_top(&mut self, pat: Option<ast::Pat>) -> PatId {
|
2022-03-04 18:49:08 +00:00
|
|
|
match pat {
|
2023-04-07 07:34:04 +00:00
|
|
|
Some(pat) => self.collect_pat(pat, &mut BindingList::default()),
|
2022-03-04 18:49:08 +00:00
|
|
|
None => self.missing_pat(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-07 07:34:04 +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
|
|
|
|
2020-04-09 21:35:05 +00:00
|
|
|
let annotation =
|
|
|
|
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
|
2023-04-07 07:34:04 +00:00
|
|
|
let subpat = bp.pat().map(|subpat| self.collect_pat(subpat, binding_list));
|
2023-03-09 14:40:51 +00:00
|
|
|
|
|
|
|
let is_simple_ident_pat =
|
|
|
|
annotation == BindingAnnotation::Unannotated && subpat.is_none();
|
|
|
|
let (binding, pattern) = if is_simple_ident_pat {
|
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.
|
2023-04-17 15:31:39 +00:00
|
|
|
let (resolved, _) = self.def_map.resolve_path(
|
2020-02-21 15:56:34 +00:00
|
|
|
self.db,
|
2023-04-17 15:31:39 +00:00
|
|
|
self.expander.module.local_id,
|
2020-02-21 15:56:34 +00:00
|
|
|
&name.clone().into(),
|
|
|
|
BuiltinShadowMode::Other,
|
2023-05-11 06:52:13 +00:00
|
|
|
None,
|
2020-02-21 15:56:34 +00:00
|
|
|
);
|
|
|
|
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
|
|
|
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-04-07 07:34:04 +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) => {
|
2023-04-07 07:34:04 +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-04-07 07:34:04 +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-04-07 07:34:04 +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-04-07 07:34:04 +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
|
|
|
}
|
|
|
|
}
|
2023-03-27 15:16:45 +00:00
|
|
|
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5676
|
|
|
|
ast::Pat::LiteralPat(lit) => 'b: {
|
|
|
|
if let Some(ast_lit) = lit.literal() {
|
2023-03-14 19:31:46 +00:00
|
|
|
let mut hir_lit: Literal = ast_lit.kind().into();
|
|
|
|
if lit.minus_token().is_some() {
|
|
|
|
let Some(h) = hir_lit.negate() else {
|
|
|
|
break 'b Pat::Missing;
|
|
|
|
};
|
|
|
|
hir_lit = h;
|
|
|
|
}
|
|
|
|
let expr = Expr::Literal(hir_lit);
|
2020-04-01 10:37:51 +00:00
|
|
|
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
|
2023-03-27 15:16:45 +00:00
|
|
|
}
|
2023-03-17 10:32:55 +00:00
|
|
|
},
|
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-04-07 07:34:04 +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) => {
|
2023-04-06 10:50:16 +00:00
|
|
|
if let Some(block) = const_block_pat.block_expr() {
|
2023-04-06 12:44:38 +00:00
|
|
|
let expr_id = self.with_label_rib(RibKind::Constant, |this| {
|
|
|
|
let syntax_ptr = AstPtr::new(&block.clone().into());
|
|
|
|
this.collect_as_a_binding_owner_bad(
|
|
|
|
|this| this.collect_block(block),
|
|
|
|
syntax_ptr,
|
|
|
|
)
|
|
|
|
});
|
2020-12-23 11:15:38 +00:00
|
|
|
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-04-07 07:34:04 +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-04-07 07:34:04 +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-04-07 07:34:04 +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-04-07 07:34:04 +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
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
// endregion: patterns
|
|
|
|
|
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);
|
|
|
|
}
|
2023-04-06 10:50:16 +00:00
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
// region: labels
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2023-04-06 10:50:16 +00:00
|
|
|
fn resolve_label(
|
|
|
|
&self,
|
|
|
|
lifetime: Option<ast::Lifetime>,
|
|
|
|
) -> Result<Option<LabelId>, BodyDiagnostic> {
|
|
|
|
let Some(lifetime) = lifetime else {
|
|
|
|
return Ok(None)
|
|
|
|
};
|
|
|
|
let name = Name::new_lifetime(&lifetime);
|
|
|
|
|
|
|
|
for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
|
|
|
|
if let Some((label_name, id)) = &rib.label {
|
|
|
|
if *label_name == name {
|
|
|
|
return if self.is_label_valid_from_rib(rib_idx) {
|
|
|
|
Ok(Some(*id))
|
|
|
|
} else {
|
|
|
|
Err(BodyDiagnostic::UnreachableLabel {
|
|
|
|
name,
|
|
|
|
node: InFile::new(
|
|
|
|
self.expander.current_file_id,
|
|
|
|
AstPtr::new(&lifetime),
|
|
|
|
),
|
|
|
|
})
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(BodyDiagnostic::UndeclaredLabel {
|
|
|
|
name,
|
|
|
|
node: InFile::new(self.expander.current_file_id, AstPtr::new(&lifetime)),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
|
|
|
|
!self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
|
|
|
|
self.label_ribs.push(LabelRib::new(kind));
|
|
|
|
let res = f(self);
|
|
|
|
self.label_ribs.pop();
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
fn with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T {
|
|
|
|
self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label)));
|
|
|
|
let res = f(self);
|
|
|
|
self.label_ribs.pop();
|
|
|
|
res
|
|
|
|
}
|
2023-04-07 07:34:04 +00:00
|
|
|
// endregion: labels
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2019-11-12 12:09:25 +00:00
|
|
|
|
2023-04-07 07:34:04 +00:00
|
|
|
impl ExprCollector<'_> {
|
|
|
|
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
|
|
|
|
let src = self.expander.to_source(ptr);
|
|
|
|
let id = self.body.exprs.alloc(expr);
|
|
|
|
self.source_map.expr_map_back.insert(id, src.clone());
|
|
|
|
self.source_map.expr_map.insert(src, id);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow.
|
|
|
|
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
|
|
|
|
self.body.exprs.alloc(expr)
|
|
|
|
}
|
|
|
|
fn missing_expr(&mut self) -> ExprId {
|
|
|
|
self.alloc_expr_desugared(Expr::Missing)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId {
|
2023-04-06 12:44:38 +00:00
|
|
|
self.body.bindings.alloc(Binding {
|
|
|
|
name,
|
|
|
|
mode,
|
|
|
|
definitions: SmallVec::new(),
|
|
|
|
owner: self.current_binding_owner,
|
|
|
|
})
|
2023-04-07 07:34:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
|
|
|
|
let src = self.expander.to_source(ptr);
|
|
|
|
let id = self.body.pats.alloc(pat);
|
|
|
|
self.source_map.pat_map_back.insert(id, src.clone());
|
|
|
|
self.source_map.pat_map.insert(src, id);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
// FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
|
|
|
|
fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId {
|
|
|
|
self.body.pats.alloc(pat)
|
|
|
|
}
|
|
|
|
fn missing_pat(&mut self) -> PatId {
|
|
|
|
self.body.pats.alloc(Pat::Missing)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
|
|
|
|
let src = self.expander.to_source(ptr);
|
|
|
|
let id = self.body.labels.alloc(label);
|
|
|
|
self.source_map.label_map_back.insert(id, src.clone());
|
|
|
|
self.source_map.label_map.insert(src, id);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
// FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
|
|
|
|
fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
|
|
|
|
self.body.labels.alloc(label)
|
2020-04-01 10:37:51 +00:00
|
|
|
}
|
|
|
|
}
|