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
|
|
|
|
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-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::{
|
2023-03-19 09:32:51 +00:00
|
|
|
self, ArrayExprKind, AstChildren, BlockExpr, 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,
|
2023-03-25 19:44:12 +00:00
|
|
|
item_tree::ItemTree,
|
2023-03-08 17:28:52 +00:00
|
|
|
lang_item::LangItem,
|
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>,
|
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-03-08 17:28:52 +00:00
|
|
|
krate,
|
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(),
|
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,
|
2022-07-21 00:00:58 +00:00
|
|
|
ast_id_map: Arc<AstIdMap>,
|
2019-11-12 15:46:57 +00:00
|
|
|
body: Body,
|
2023-03-08 17:28:52 +00:00
|
|
|
krate: CrateId,
|
2019-11-12 15:46:57 +00:00
|
|
|
source_map: BodySourceMap,
|
2023-04-06 10:50:16 +00:00
|
|
|
current_try_block_label: Option<LabelId>,
|
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-06 10:50:16 +00:00
|
|
|
label_ribs: Vec<LabelRib>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
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<'_> {
|
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
|
|
|
|
}
|
2023-03-08 17:28:52 +00:00
|
|
|
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow.
|
2019-11-12 15:46:57 +00:00
|
|
|
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
|
|
|
|
}
|
2023-03-08 17:28:52 +00:00
|
|
|
// 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)
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
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
|
|
|
|
}
|
2023-03-19 09:32:51 +00:00
|
|
|
// 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-12-23 15:34:30 +00:00
|
|
|
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
|
|
|
|
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) => {
|
|
|
|
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() {
|
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| {
|
|
|
|
this.collect_block_(e, |id, statements, tail| Expr::Const {
|
|
|
|
id,
|
|
|
|
statements,
|
|
|
|
tail,
|
|
|
|
})
|
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());
|
|
|
|
let pat = self.collect_pat_opt(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) => {
|
|
|
|
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
|
|
|
}
|
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| {
|
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-06 10:50:16 +00:00
|
|
|
let pat = this.collect_pat_opt(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-06 10:50:16 +00:00
|
|
|
let prev_is_lowering_generator = this.is_lowering_generator;
|
|
|
|
this.is_lowering_generator = false;
|
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 10:50:16 +00:00
|
|
|
this.is_lowering_generator = prev_is_lowering_generator;
|
2022-09-05 13:43:26 +00:00
|
|
|
|
2023-04-06 10:50:16 +00:00
|
|
|
this.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,
|
|
|
|
)
|
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| {
|
|
|
|
this.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
|
|
|
|
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));
|
|
|
|
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,
|
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 {
|
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-03-05 13:08:23 +00:00
|
|
|
|
2023-03-25 19:44:12 +00:00
|
|
|
let block_id = if ItemTree::block_has_items(self.db, ast_id.file_id, &block) {
|
|
|
|
Some(self.db.intern_block(BlockLoc {
|
|
|
|
ast_id,
|
|
|
|
module: self.expander.def_map.module_id(self.expander.module),
|
|
|
|
}))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let (module, def_map) = match block_id
|
|
|
|
.and_then(|block_id| self.db.block_def_map(block_id).zip(Some(block_id)))
|
|
|
|
{
|
|
|
|
Some((def_map, block_id)) => {
|
2021-04-04 01:16:26 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-03-09 14:40:51 +00:00
|
|
|
self.collect_pat_(pat, &mut BindingList::default())
|
2022-03-04 18:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
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));
|
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.
|
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
|
|
|
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) => {
|
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
|
|
|
}
|
|
|
|
}
|
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-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) => {
|
2023-04-06 10:50:16 +00:00
|
|
|
if let Some(block) = const_block_pat.block_expr() {
|
|
|
|
let expr_id =
|
|
|
|
self.with_label_rib(RibKind::Constant, |this| this.collect_block(block));
|
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-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);
|
|
|
|
}
|
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
|
|
|
|
}
|
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,
|
|
|
|
)
|
2023-03-14 19:31:46 +00:00
|
|
|
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) {
|
2021-05-12 12:59:35 +00:00
|
|
|
Literal::Uint(lit.value().unwrap_or(0), builtin)
|
2023-03-14 19:31:46 +00:00
|
|
|
} else {
|
|
|
|
let builtin = lit.suffix().and_then(BuiltinInt::from_suffix);
|
|
|
|
Literal::Int(lit.value().unwrap_or(0) as i128, 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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|