2019-11-24 17:39:48 +00:00
|
|
|
//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
|
|
|
|
//! representation.
|
2019-11-12 12:09:25 +00:00
|
|
|
|
2021-04-10 15:49:12 +00:00
|
|
|
use std::{mem, sync::Arc};
|
2020-07-31 17:54:16 +00:00
|
|
|
|
2019-12-03 16:07:56 +00:00
|
|
|
use either::Either;
|
2020-03-14 06:25:30 +00:00
|
|
|
use hir_expand::{
|
2021-04-10 15:49:12 +00:00
|
|
|
ast_id_map::{AstIdMap, FileAstId},
|
2020-04-30 10:20:13 +00:00
|
|
|
hygiene::Hygiene,
|
2020-03-14 06:25:30 +00:00
|
|
|
name::{name, AsName, Name},
|
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
|
|
|
ExpandError, HirFileId, InFile,
|
2020-03-14 06:25:30 +00:00
|
|
|
};
|
2021-01-14 15:47:42 +00:00
|
|
|
use la_arena::Arena;
|
2021-01-27 09:16:24 +00:00
|
|
|
use profile::Count;
|
2020-08-12 16:26:51 +00:00
|
|
|
use syntax::{
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::{
|
2021-09-27 10:54:24 +00:00
|
|
|
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
|
2020-07-30 18:51:43 +00:00
|
|
|
SlicePatComponents,
|
2019-11-12 15:46:57 +00:00
|
|
|
},
|
2020-10-23 17:27:04 +00:00
|
|
|
AstNode, AstPtr, SyntaxNodePtr,
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
2019-11-12 12:09:25 +00:00
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
use crate::{
|
2020-02-21 15:56:34 +00:00
|
|
|
adt::StructKind,
|
2020-12-23 15:34:30 +00:00
|
|
|
body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
|
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::{
|
2021-08-14 15:08:31 +00:00
|
|
|
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
|
|
|
|
MatchGuard, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
2019-11-12 15:46:57 +00:00
|
|
|
},
|
2021-04-06 14:07:45 +00:00
|
|
|
intern::Interned,
|
2020-02-21 15:56:34 +00:00
|
|
|
item_scope::BuiltinShadowMode,
|
2020-04-30 10:20:13 +00:00
|
|
|
path::{GenericArgs, Path},
|
2020-05-28 19:42:22 +00:00
|
|
|
type_ref::{Mutability, Rawness, TypeRef},
|
2021-03-16 07:46:57 +00:00
|
|
|
AdtId, 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,
|
2021-04-10 15:49:12 +00:00
|
|
|
file_id: Option<HirFileId>,
|
|
|
|
source_ast_id_map: Option<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),
|
|
|
|
file_id: Some(file_id),
|
|
|
|
source_ast_id_map: Some(db.ast_id_map(file_id)),
|
|
|
|
}
|
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 {
|
|
|
|
LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
|
2021-04-10 15:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn hygiene(&self) -> &Hygiene {
|
|
|
|
&self.hygiene
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn file_id(&self) -> HirFileId {
|
|
|
|
self.file_id.unwrap()
|
2020-04-30 10:20:13 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
|
|
|
|
self.source_ast_id_map.as_ref().map(|ast_id_map| 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,
|
2019-11-12 15:46:57 +00:00
|
|
|
params: Option<ast::ParamList>,
|
|
|
|
body: Option<ast::Expr>,
|
|
|
|
) -> (Body, BodySourceMap) {
|
|
|
|
ExprCollector {
|
|
|
|
db,
|
|
|
|
source_map: BodySourceMap::default(),
|
|
|
|
body: Body {
|
|
|
|
exprs: Arena::default(),
|
|
|
|
pats: 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,
|
2021-03-25 19:52:35 +00:00
|
|
|
statements_in_scope: Vec::new(),
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
.collect(params, body)
|
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
struct ExprCollector<'a> {
|
|
|
|
db: &'a dyn DefDatabase,
|
2019-11-14 06:38:25 +00:00
|
|
|
expander: Expander,
|
2019-11-12 15:46:57 +00:00
|
|
|
body: Body,
|
|
|
|
source_map: BodySourceMap,
|
2021-03-25 19:52:35 +00:00
|
|
|
statements_in_scope: Vec<Statement>,
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl ExprCollector<'_> {
|
2019-11-12 15:46:57 +00:00
|
|
|
fn collect(
|
|
|
|
mut self,
|
|
|
|
param_list: Option<ast::ParamList>,
|
|
|
|
body: Option<ast::Expr>,
|
|
|
|
) -> (Body, BodySourceMap) {
|
|
|
|
if let Some(param_list) = param_list {
|
|
|
|
if let Some(self_param) = param_list.self_param() {
|
|
|
|
let ptr = AstPtr::new(&self_param);
|
|
|
|
let param_pat = self.alloc_pat(
|
|
|
|
Pat::Bind {
|
2019-12-13 21:01:06 +00:00
|
|
|
name: name![self],
|
2020-10-11 16:27:38 +00:00
|
|
|
mode: BindingAnnotation::new(
|
|
|
|
self_param.mut_token().is_some() && self_param.amp_token().is_none(),
|
|
|
|
false,
|
|
|
|
),
|
2019-11-12 15:46:57 +00:00
|
|
|
subpat: None,
|
|
|
|
},
|
2019-12-03 16:07:56 +00:00
|
|
|
Either::Right(ptr),
|
2019-11-12 15:46:57 +00:00
|
|
|
);
|
|
|
|
self.body.params.push(param_pat);
|
|
|
|
}
|
|
|
|
|
|
|
|
for param in param_list.params() {
|
|
|
|
let pat = match param.pat() {
|
|
|
|
None => continue,
|
|
|
|
Some(pat) => pat,
|
|
|
|
};
|
|
|
|
let param_pat = self.collect_pat(pat);
|
|
|
|
self.body.params.push(param_pat);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.body.body_expr = self.collect_expr_opt(body);
|
|
|
|
(self.body, self.source_map)
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
|
2019-11-14 07:30:30 +00:00
|
|
|
let src = self.expander.to_source(ptr);
|
2020-04-10 22:27:00 +00:00
|
|
|
let id = self.make_expr(expr, Ok(src.clone()));
|
2019-11-14 07:30:30 +00:00
|
|
|
self.source_map.expr_map.insert(src, id);
|
2019-11-12 15:46:57 +00:00
|
|
|
id
|
|
|
|
}
|
|
|
|
// desugared exprs don't have ptr, that's wrong and should be fixed
|
|
|
|
// somehow.
|
|
|
|
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
|
2020-03-06 14:11:05 +00:00
|
|
|
self.make_expr(expr, Err(SyntheticSyntax))
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2021-02-01 12:19:55 +00:00
|
|
|
fn unit(&mut self) -> ExprId {
|
|
|
|
self.alloc_expr_desugared(Expr::Tuple { exprs: Vec::new() })
|
2020-03-06 14:11:05 +00:00
|
|
|
}
|
|
|
|
fn missing_expr(&mut self) -> ExprId {
|
|
|
|
self.alloc_expr_desugared(Expr::Missing)
|
|
|
|
}
|
|
|
|
fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
|
|
|
|
let id = self.body.exprs.alloc(expr);
|
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
|
|
|
|
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);
|
2020-04-10 22:27:00 +00:00
|
|
|
let id = self.make_pat(pat, Ok(src.clone()));
|
2019-11-14 07:30:30 +00:00
|
|
|
self.source_map.pat_map.insert(src, id);
|
2019-11-12 15:46:57 +00:00
|
|
|
id
|
|
|
|
}
|
|
|
|
fn missing_pat(&mut self) -> PatId {
|
2020-03-06 14:17:48 +00:00
|
|
|
self.make_pat(Pat::Missing, Err(SyntheticSyntax))
|
|
|
|
}
|
|
|
|
fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
|
|
|
|
let id = self.body.pats.alloc(pat);
|
|
|
|
self.source_map.pat_map_back.insert(id, src);
|
|
|
|
id
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
2020-12-23 15:34:30 +00:00
|
|
|
fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
|
|
|
|
let src = self.expander.to_source(ptr);
|
|
|
|
let id = self.make_label(label, src.clone());
|
|
|
|
self.source_map.label_map.insert(src, id);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
|
|
|
|
let id = self.body.labels.alloc(label);
|
|
|
|
self.source_map.label_map_back.insert(id, src);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
|
2021-03-17 14:08:46 +00:00
|
|
|
self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
|
|
|
|
}
|
|
|
|
|
2021-04-07 11:45:17 +00:00
|
|
|
/// Returns `None` if and only if the expression is `#[cfg]`d out.
|
2021-03-17 14:08:46 +00:00
|
|
|
fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
|
2019-11-12 15:46:57 +00:00
|
|
|
let syntax_ptr = AstPtr::new(&expr);
|
2021-03-17 14:08:46 +00:00
|
|
|
self.check_cfg(&expr)?;
|
2020-05-28 02:21:20 +00:00
|
|
|
|
2021-03-17 14:08:46 +00:00
|
|
|
Some(match expr {
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::IfExpr(e) => {
|
|
|
|
let then_branch = self.collect_block_opt(e.then_branch());
|
|
|
|
|
|
|
|
let else_branch = e.else_branch().map(|b| match b {
|
|
|
|
ast::ElseBranch::Block(it) => self.collect_block(it),
|
|
|
|
ast::ElseBranch::IfExpr(elif) => {
|
|
|
|
let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
|
|
|
|
self.collect_expr(expr)
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let condition = match e.condition() {
|
|
|
|
None => self.missing_expr(),
|
|
|
|
Some(condition) => match condition.pat() {
|
|
|
|
None => self.collect_expr_opt(condition.expr()),
|
|
|
|
// if let -- desugar to match
|
|
|
|
Some(pat) => {
|
|
|
|
let pat = self.collect_pat(pat);
|
|
|
|
let match_expr = self.collect_expr_opt(condition.expr());
|
|
|
|
let placeholder_pat = self.missing_pat();
|
|
|
|
let arms = vec![
|
2020-02-09 18:57:01 +00:00
|
|
|
MatchArm { pat, expr: then_branch, guard: None },
|
2019-11-12 15:46:57 +00:00
|
|
|
MatchArm {
|
2020-02-09 18:57:01 +00:00
|
|
|
pat: placeholder_pat,
|
2021-02-01 12:19:55 +00:00
|
|
|
expr: else_branch.unwrap_or_else(|| self.unit()),
|
2019-11-12 15:46:57 +00:00
|
|
|
guard: None,
|
|
|
|
},
|
|
|
|
];
|
2021-03-17 14:08:46 +00:00
|
|
|
return Some(
|
|
|
|
self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
|
|
|
|
);
|
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
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
ast::Expr::BlockExpr(e) => match e.modifier() {
|
|
|
|
Some(ast::BlockModifier::Try(_)) => {
|
|
|
|
let body = self.collect_block(e);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
|
2020-05-01 23:18:19 +00:00
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
Some(ast::BlockModifier::Unsafe(_)) => {
|
|
|
|
let body = self.collect_block(e);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
|
2020-05-24 20:24:36 +00:00
|
|
|
}
|
2020-05-01 23:18:19 +00:00
|
|
|
// FIXME: we need to record these effects somewhere...
|
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);
|
2021-09-26 09:12:57 +00:00
|
|
|
let res = self.collect_block(e);
|
|
|
|
match &mut self.body.exprs[res] {
|
|
|
|
Expr::Block { label: block_label, .. } => {
|
|
|
|
*block_label = Some(label);
|
2020-07-31 14:52:08 +00:00
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
_ => unreachable!(),
|
2020-07-31 14:52:08 +00:00
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
res
|
2020-12-23 15:34:30 +00:00
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
Some(ast::BlockModifier::Async(_)) => {
|
|
|
|
let body = self.collect_block(e);
|
2020-09-10 12:01:23 +00:00
|
|
|
self.alloc_expr(Expr::Async { body }, syntax_ptr)
|
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
Some(ast::BlockModifier::Const(_)) => {
|
|
|
|
let body = self.collect_block(e);
|
2020-12-23 11:24:24 +00:00
|
|
|
self.alloc_expr(Expr::Const { body }, syntax_ptr)
|
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
None => self.collect_block(e),
|
2020-05-01 23:18:19 +00:00
|
|
|
},
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::LoopExpr(e) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = e.label().map(|label| self.collect_label(label));
|
2019-11-12 15:46:57 +00:00
|
|
|
let body = self.collect_block_opt(e.loop_body());
|
2020-12-23 15:34:30 +00:00
|
|
|
self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::WhileExpr(e) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = e.label().map(|label| self.collect_label(label));
|
2019-11-12 15:46:57 +00:00
|
|
|
let body = self.collect_block_opt(e.loop_body());
|
|
|
|
|
|
|
|
let condition = match e.condition() {
|
|
|
|
None => self.missing_expr(),
|
|
|
|
Some(condition) => match condition.pat() {
|
|
|
|
None => self.collect_expr_opt(condition.expr()),
|
|
|
|
// if let -- desugar to match
|
|
|
|
Some(pat) => {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(infer_resolve_while_let);
|
2019-11-12 15:46:57 +00:00
|
|
|
let pat = self.collect_pat(pat);
|
|
|
|
let match_expr = self.collect_expr_opt(condition.expr());
|
|
|
|
let placeholder_pat = self.missing_pat();
|
2020-05-31 08:59:40 +00:00
|
|
|
let break_ =
|
|
|
|
self.alloc_expr_desugared(Expr::Break { expr: None, label: None });
|
2019-11-12 15:46:57 +00:00
|
|
|
let arms = vec![
|
2020-02-09 18:57:01 +00:00
|
|
|
MatchArm { pat, expr: body, guard: None },
|
|
|
|
MatchArm { pat: placeholder_pat, expr: break_, guard: None },
|
2019-11-12 15:46:57 +00:00
|
|
|
];
|
|
|
|
let match_expr =
|
|
|
|
self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
|
2021-03-17 14:08:46 +00:00
|
|
|
return Some(
|
|
|
|
self.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr),
|
|
|
|
);
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-12-23 15:34:30 +00:00
|
|
|
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::ForExpr(e) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = e.label().map(|label| self.collect_label(label));
|
2019-11-12 15:46:57 +00:00
|
|
|
let iterable = self.collect_expr_opt(e.iterable());
|
|
|
|
let pat = self.collect_pat_opt(e.pat());
|
|
|
|
let body = self.collect_block_opt(e.loop_body());
|
2020-12-23 15:34:30 +00:00
|
|
|
self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::CallExpr(e) => {
|
|
|
|
let callee = self.collect_expr_opt(e.expr());
|
|
|
|
let args = if let Some(arg_list) = e.arg_list() {
|
2021-03-17 14:08:46 +00:00
|
|
|
arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
|
2019-11-12 15:46:57 +00:00
|
|
|
} else {
|
|
|
|
Vec::new()
|
|
|
|
};
|
2020-06-02 23:09:51 +00:00
|
|
|
self.alloc_expr(Expr::Call { callee, args }, 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 {
|
2020-06-02 23:09:51 +00:00
|
|
|
Vec::new()
|
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()),
|
2021-08-12 22:21:42 +00:00
|
|
|
guard: arm.guard().map(|guard| match guard.pat() {
|
|
|
|
Some(pat) => MatchGuard::IfLet {
|
|
|
|
pat: self.collect_pat(pat),
|
|
|
|
expr: self.collect_expr_opt(guard.expr()),
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
MatchGuard::If { expr: self.collect_expr_opt(guard.expr()) }
|
|
|
|
}
|
|
|
|
}),
|
2020-10-23 17:27:04 +00:00
|
|
|
})
|
2020-06-02 22:44:04 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
} else {
|
2020-06-02 23:09:51 +00:00
|
|
|
Vec::new()
|
2020-06-02 22:44:04 +00:00
|
|
|
};
|
|
|
|
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::PathExpr(e) => {
|
|
|
|
let path = e
|
|
|
|
.path()
|
2021-05-06 17:59:54 +00:00
|
|
|
.and_then(|path| self.expander.parse_path(self.db, path))
|
2019-11-12 15:46:57 +00:00
|
|
|
.map(Expr::Path)
|
|
|
|
.unwrap_or(Expr::Missing);
|
2020-05-29 12:55:47 +00:00
|
|
|
self.alloc_expr(path, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2020-06-02 22:04:23 +00:00
|
|
|
ast::Expr::ContinueExpr(e) => self.alloc_expr(
|
2020-12-15 18:23:51 +00:00
|
|
|
Expr::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
|
2020-05-31 10:06:22 +00:00
|
|
|
syntax_ptr,
|
2020-06-02 22:04:23 +00:00
|
|
|
),
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::BreakExpr(e) => {
|
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(
|
2020-12-15 18:23:51 +00:00
|
|
|
Expr::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
|
2020-05-31 08:59:40 +00:00
|
|
|
syntax_ptr,
|
2020-06-02 22:44:04 +00:00
|
|
|
)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::ParenExpr(e) => {
|
|
|
|
let inner = self.collect_expr_opt(e.expr());
|
|
|
|
// make the paren expr point to the inner expression as well
|
2020-04-11 17:25:33 +00:00
|
|
|
let src = self.expander.to_source(syntax_ptr);
|
2019-11-14 07:30:30 +00:00
|
|
|
self.source_map.expr_map.insert(src, inner);
|
2020-05-29 12:55:47 +00:00
|
|
|
inner
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::ReturnExpr(e) => {
|
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2021-01-13 15:01:50 +00:00
|
|
|
ast::Expr::YieldExpr(e) => {
|
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
|
|
|
self.alloc_expr(Expr::Yield { 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);
|
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));
|
2020-06-02 23:09:51 +00:00
|
|
|
Expr::RecordLit { path, fields, spread }
|
2019-11-12 15:46:57 +00:00
|
|
|
} else {
|
2020-06-02 22:44:04 +00:00
|
|
|
Expr::RecordLit { path, fields: Vec::new(), spread: None }
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
|
|
|
|
2021-03-15 12:38:50 +00:00
|
|
|
self.alloc_expr(record_lit, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::FieldExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
|
|
|
let name = match e.field_access() {
|
|
|
|
Some(kind) => kind.as_name(),
|
|
|
|
_ => Name::missing(),
|
|
|
|
};
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::AwaitExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Await { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::TryExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Try { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::CastExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2021-04-06 14:07:45 +00:00
|
|
|
let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::RefExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-05-28 19:42:22 +00:00
|
|
|
let raw_tok = e.raw_token().is_some();
|
|
|
|
let mutability = if raw_tok {
|
|
|
|
if e.mut_token().is_some() {
|
|
|
|
Mutability::Mut
|
|
|
|
} else if e.const_token().is_some() {
|
|
|
|
Mutability::Shared
|
|
|
|
} else {
|
|
|
|
unreachable!("parser only remaps to raw_token() if matching mutability token follows")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Mutability::from_mutable(e.mut_token().is_some())
|
|
|
|
};
|
|
|
|
let rawness = Rawness::from_raw(raw_tok);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::PrefixExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
|
|
|
if let Some(op) = e.op_kind() {
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
} else {
|
2020-05-29 12:55:47 +00:00
|
|
|
self.alloc_expr(Expr::Missing, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-31 15:08:58 +00:00
|
|
|
ast::Expr::ClosureExpr(e) => {
|
2019-11-12 15:46:57 +00:00
|
|
|
let mut args = Vec::new();
|
|
|
|
let mut arg_types = Vec::new();
|
|
|
|
if let Some(pl) = e.param_list() {
|
|
|
|
for param in pl.params() {
|
|
|
|
let pat = self.collect_pat_opt(param.pat());
|
2021-04-06 14:07:45 +00:00
|
|
|
let type_ref =
|
|
|
|
param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
2019-11-12 15:46:57 +00:00
|
|
|
args.push(pat);
|
|
|
|
arg_types.push(type_ref);
|
|
|
|
}
|
|
|
|
}
|
2021-03-30 20:06:57 +00:00
|
|
|
let ret_type = e
|
|
|
|
.ret_type()
|
|
|
|
.and_then(|r| r.ty())
|
2021-04-06 14:07:45 +00:00
|
|
|
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
2019-11-12 15:46:57 +00:00
|
|
|
let body = self.collect_expr_opt(e.body());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::BinExpr(e) => {
|
|
|
|
let lhs = self.collect_expr_opt(e.lhs());
|
|
|
|
let rhs = self.collect_expr_opt(e.rhs());
|
2021-08-14 15:08:31 +00:00
|
|
|
let op = e.op_kind();
|
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();
|
2020-06-02 23:09:51 +00:00
|
|
|
self.alloc_expr(Expr::Tuple { exprs }, 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) => {
|
2020-06-02 23:09:51 +00:00
|
|
|
let exprs = e.map(|expr| self.collect_expr(expr)).collect();
|
|
|
|
self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ArrayExprKind::Repeat { initializer, repeat } => {
|
|
|
|
let initializer = self.collect_expr_opt(initializer);
|
|
|
|
let repeat = self.collect_expr_opt(repeat);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(
|
|
|
|
Expr::Array(Array::Repeat { initializer, repeat }),
|
|
|
|
syntax_ptr,
|
2019-11-12 15:46:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 12:55:47 +00:00
|
|
|
ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::IndexExpr(e) => {
|
|
|
|
let base = self.collect_expr_opt(e.base());
|
|
|
|
let index = self.collect_expr_opt(e.index());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2019-11-28 19:10:16 +00:00
|
|
|
ast::Expr::RangeExpr(e) => {
|
|
|
|
let lhs = e.start().map(|lhs| self.collect_expr(lhs));
|
|
|
|
let rhs = e.end().map(|rhs| self.collect_expr(rhs));
|
2019-11-29 06:49:12 +00:00
|
|
|
match e.op_kind() {
|
2020-06-02 22:44:04 +00:00
|
|
|
Some(range_type) => {
|
|
|
|
self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
|
|
|
|
}
|
2020-05-29 12:55:47 +00:00
|
|
|
None => self.alloc_expr(Expr::Missing, syntax_ptr),
|
2019-11-28 19:10:16 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-23 13:47:11 +00:00
|
|
|
ast::Expr::MacroCall(e) => {
|
2021-04-10 21:12:02 +00:00
|
|
|
let macro_ptr = AstPtr::new(&e);
|
2020-12-15 06:39:15 +00:00
|
|
|
let mut ids = vec![];
|
2021-09-05 22:16:12 +00:00
|
|
|
self.collect_macro_call(e, macro_ptr, |this, expansion| {
|
2020-12-15 06:39:15 +00:00
|
|
|
ids.push(match expansion {
|
|
|
|
Some(it) => this.collect_expr(it),
|
|
|
|
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
ids[0]
|
|
|
|
}
|
2021-03-16 05:44:50 +00:00
|
|
|
ast::Expr::MacroStmts(e) => {
|
2021-03-25 19:52:35 +00:00
|
|
|
e.statements().for_each(|s| self.collect_stmt(s));
|
|
|
|
let tail = e
|
|
|
|
.expr()
|
|
|
|
.map(|e| self.collect_expr(e))
|
|
|
|
.unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
|
|
|
|
|
|
|
|
self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
2021-03-17 14:08:46 +00:00
|
|
|
})
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
2020-11-30 19:26:35 +00:00
|
|
|
|
2020-12-15 06:39:15 +00:00
|
|
|
fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
|
|
|
|
&mut self,
|
|
|
|
e: ast::MacroCall,
|
2021-04-10 21:12:02 +00:00
|
|
|
syntax_ptr: AstPtr<ast::MacroCall>,
|
2020-12-15 06:39:15 +00:00
|
|
|
mut collector: F,
|
|
|
|
) {
|
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
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
let macro_call = self.expander.to_source(AstPtr::new(&e));
|
2021-02-01 12:19:55 +00:00
|
|
|
let res = self.expander.enter_expand(self.db, e);
|
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 }) => {
|
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::UnresolvedMacroCall {
|
|
|
|
node: InFile::new(outer_file, syntax_ptr),
|
|
|
|
path,
|
|
|
|
});
|
2021-03-16 07:46:57 +00:00
|
|
|
collector(self, None);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
match &res.err {
|
|
|
|
Some(ExpandError::UnresolvedProcMacro) => {
|
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::UnresolvedProcMacro {
|
|
|
|
node: InFile::new(outer_file, syntax_ptr),
|
|
|
|
});
|
2020-12-15 14:37:37 +00:00
|
|
|
}
|
|
|
|
Some(err) => {
|
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::MacroError {
|
|
|
|
node: InFile::new(outer_file, syntax_ptr),
|
2020-12-15 14:37:37 +00:00
|
|
|
message: err.to_string(),
|
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-12-15 06:39:15 +00:00
|
|
|
}
|
2020-12-15 14:37:37 +00:00
|
|
|
None => {}
|
|
|
|
}
|
2020-12-15 06:39:15 +00:00
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
match res.value {
|
|
|
|
Some((mark, expansion)) => {
|
2021-09-05 22:16:12 +00:00
|
|
|
self.source_map.expansions.insert(macro_call, 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));
|
|
|
|
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 {
|
|
|
|
if let Some(expr) = expr {
|
|
|
|
self.collect_expr(expr)
|
|
|
|
} else {
|
|
|
|
self.missing_expr()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-25 19:52:35 +00:00
|
|
|
fn collect_stmt(&mut self, s: ast::Stmt) {
|
|
|
|
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() {
|
|
|
|
return;
|
|
|
|
}
|
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-03-25 19:52:35 +00:00
|
|
|
self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
|
|
|
ast::Stmt::ExprStmt(stmt) => {
|
2021-09-25 16:51:54 +00:00
|
|
|
if let Some(expr) = stmt.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();
|
2021-03-16 05:44:50 +00:00
|
|
|
// Note that macro could be expended to multiple statements
|
|
|
|
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
|
2021-04-10 21:12:02 +00:00
|
|
|
let macro_ptr = AstPtr::new(&m);
|
2021-03-16 05:44:50 +00:00
|
|
|
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
|
|
|
|
2021-09-05 22:16:12 +00:00
|
|
|
self.collect_macro_call(m, macro_ptr, |this, expansion| match expansion {
|
|
|
|
Some(expansion) => {
|
|
|
|
let statements: ast::MacroStmts = expansion;
|
|
|
|
|
|
|
|
statements.statements().for_each(|stmt| this.collect_stmt(stmt));
|
|
|
|
if let Some(expr) = statements.expr() {
|
|
|
|
let expr = this.collect_expr(expr);
|
2021-04-07 11:45:17 +00:00
|
|
|
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
2021-09-05 22:16:12 +00:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
|
|
|
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
|
|
|
}
|
|
|
|
});
|
2021-03-16 05:44:50 +00:00
|
|
|
} else {
|
2021-03-25 19:52:35 +00:00
|
|
|
let expr = self.collect_expr_opt(stmt.expr());
|
2021-04-07 11:45:17 +00:00
|
|
|
self.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
|
|
|
ast::Stmt::Item(item) => {
|
2021-06-07 11:59:01 +00:00
|
|
|
self.check_cfg(&item);
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
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 {
|
2021-02-01 12:19:55 +00:00
|
|
|
let ast_id = self.expander.ast_id(&block);
|
2021-02-04 14:04:21 +00:00
|
|
|
let block_loc =
|
|
|
|
BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
|
2021-02-01 12:19:55 +00:00
|
|
|
let block_id = self.db.intern_block(block_loc);
|
2021-03-05 13:08:23 +00:00
|
|
|
|
2021-04-04 01:16:26 +00:00
|
|
|
let (module, def_map) = match self.db.block_def_map(block_id) {
|
|
|
|
Some(def_map) => {
|
|
|
|
self.body.block_scopes.push(block_id);
|
|
|
|
(def_map.root(), def_map)
|
|
|
|
}
|
|
|
|
None => (self.expander.module, self.expander.def_map.clone()),
|
|
|
|
};
|
2021-02-01 12:19:55 +00:00
|
|
|
let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
|
2021-02-04 14:04:21 +00:00
|
|
|
let prev_local_module = mem::replace(&mut self.expander.module, module);
|
2021-03-25 19:52:35 +00:00
|
|
|
let prev_statements = std::mem::take(&mut self.statements_in_scope);
|
|
|
|
|
|
|
|
block.statements().for_each(|s| self.collect_stmt(s));
|
2021-04-07 11:45:17 +00:00
|
|
|
block.tail_expr().and_then(|e| {
|
|
|
|
let expr = self.maybe_collect_expr(e)?;
|
2021-06-07 11:59:01 +00:00
|
|
|
self.statements_in_scope.push(Statement::Expr { expr, has_semi: false });
|
|
|
|
Some(())
|
2021-04-07 11:45:17 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let mut tail = None;
|
|
|
|
if let Some(Statement::Expr { expr, has_semi: false }) = self.statements_in_scope.last() {
|
|
|
|
tail = Some(*expr);
|
|
|
|
self.statements_in_scope.pop();
|
|
|
|
}
|
|
|
|
let tail = tail;
|
2021-03-25 19:52:35 +00:00
|
|
|
let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
|
2021-02-05 15:57:26 +00:00
|
|
|
let syntax_node_ptr = AstPtr::new(&block.into());
|
2021-02-01 12:19:55 +00:00
|
|
|
let expr_id = self.alloc_expr(
|
|
|
|
Expr::Block { id: block_id, statements, tail, label: None },
|
|
|
|
syntax_node_ptr,
|
|
|
|
);
|
|
|
|
|
|
|
|
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 {
|
|
|
|
if let Some(block) = expr {
|
|
|
|
self.collect_block(block)
|
|
|
|
} else {
|
|
|
|
self.missing_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 {
|
|
|
|
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);
|
2020-04-09 21:35:05 +00:00
|
|
|
let annotation =
|
|
|
|
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
|
2019-11-12 15:46:57 +00:00
|
|
|
let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
|
2020-02-21 15:56:34 +00:00
|
|
|
if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
|
|
|
|
// This could also be a single-segment path pattern. To
|
|
|
|
// decide that, we need to try resolving the name.
|
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() {
|
|
|
|
Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
|
|
|
|
Some(ModuleDefId::EnumVariantId(_)) => {
|
|
|
|
// this is only really valid for unit variants, but
|
|
|
|
// shadowing other enum variants with a pattern is
|
|
|
|
// an error anyway
|
|
|
|
Pat::Path(name.into())
|
|
|
|
}
|
|
|
|
Some(ModuleDefId::AdtId(AdtId::StructId(s)))
|
|
|
|
if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
|
|
|
|
{
|
|
|
|
// Funnily enough, record structs *can* be shadowed
|
|
|
|
// by pattern bindings (but unit or tuple structs
|
|
|
|
// can't).
|
|
|
|
Pat::Path(name.into())
|
|
|
|
}
|
|
|
|
// shadowing statics is an error as well, so we just ignore that case here
|
|
|
|
_ => Pat::Bind { name, mode: annotation, subpat },
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Pat::Bind { name, mode: annotation, subpat }
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Pat::TupleStructPat(p) => {
|
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);
|
2020-07-31 19:58:36 +00:00
|
|
|
let (args, ellipsis) = self.collect_tuple_pat(p.fields());
|
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) => {
|
|
|
|
let pat = self.collect_pat_opt(p.pat());
|
2020-04-09 21:35:05 +00:00
|
|
|
let mutability = Mutability::from_mutable(p.mut_token().is_some());
|
2019-11-12 15:46:57 +00:00
|
|
|
Pat::Ref { pat, mutability }
|
|
|
|
}
|
|
|
|
ast::Pat::PathPat(p) => {
|
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) => {
|
|
|
|
let pats = p.pats().map(|p| self.collect_pat(p)).collect();
|
|
|
|
Pat::Or(pats)
|
|
|
|
}
|
|
|
|
ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Pat::TuplePat(p) => {
|
2020-07-31 19:58:36 +00:00
|
|
|
let (args, ellipsis) = self.collect_tuple_pat(p.fields());
|
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);
|
2020-07-31 17:54:16 +00:00
|
|
|
let args: Vec<_> = p
|
|
|
|
.record_pat_field_list()
|
|
|
|
.expect("every struct should have a field list")
|
|
|
|
.fields()
|
|
|
|
.filter_map(|f| {
|
|
|
|
let ast_pat = f.pat()?;
|
2019-11-12 15:46:57 +00:00
|
|
|
let pat = self.collect_pat(ast_pat);
|
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")
|
|
|
|
.dotdot_token()
|
|
|
|
.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 {
|
|
|
|
prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(),
|
|
|
|
slice: slice.map(|p| self.collect_pat(p)),
|
|
|
|
suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(),
|
|
|
|
}
|
|
|
|
}
|
2020-04-01 10:37:51 +00:00
|
|
|
ast::Pat::LiteralPat(lit) => {
|
|
|
|
if let Some(ast_lit) = lit.literal() {
|
|
|
|
let expr = Expr::Literal(ast_lit.kind().into());
|
|
|
|
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
|
|
|
|
let expr_id = self.alloc_expr(expr, expr_ptr);
|
|
|
|
Pat::Lit(expr_id)
|
|
|
|
} else {
|
|
|
|
Pat::Missing
|
|
|
|
}
|
|
|
|
}
|
2020-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) => {
|
|
|
|
let inner = self.collect_pat_opt(boxpat.pat());
|
|
|
|
Pat::Box { inner }
|
|
|
|
}
|
2020-12-23 11:15:38 +00:00
|
|
|
ast::Pat::ConstBlockPat(const_block_pat) => {
|
|
|
|
if let Some(expr) = const_block_pat.block_expr() {
|
|
|
|
let expr_id = self.collect_block(expr);
|
|
|
|
Pat::ConstBlock(expr_id)
|
|
|
|
} else {
|
|
|
|
Pat::Missing
|
|
|
|
}
|
2020-12-23 00:26:31 +00:00
|
|
|
}
|
2021-04-10 21:12:02 +00:00
|
|
|
ast::Pat::MacroPat(mac) => match mac.macro_call() {
|
|
|
|
Some(call) => {
|
|
|
|
let macro_ptr = AstPtr::new(&call);
|
|
|
|
let mut pat = None;
|
2021-09-05 22:16:12 +00:00
|
|
|
self.collect_macro_call(call, macro_ptr, |this, expanded_pat| {
|
2021-04-10 21:12:02 +00:00
|
|
|
pat = Some(this.collect_pat_opt(expanded_pat));
|
|
|
|
});
|
|
|
|
|
|
|
|
match pat {
|
|
|
|
Some(pat) => return pat,
|
|
|
|
None => Pat::Missing,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
|
|
|
|
if let Some(pat) = pat {
|
|
|
|
self.collect_pat(pat)
|
|
|
|
} else {
|
|
|
|
self.missing_pat()
|
|
|
|
}
|
|
|
|
}
|
2020-04-12 15:40:09 +00:00
|
|
|
|
|
|
|
fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
|
|
|
|
// Find the location of the `..`, if there is one. Note that we do not
|
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(_)))
|
2020-04-12 15:40:09 +00:00
|
|
|
.map(|p| self.collect_pat(p))
|
|
|
|
.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(()),
|
|
|
|
}
|
|
|
|
}
|
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) {
|
2021-06-13 04:05:29 +00:00
|
|
|
Literal::Float(Default::default(), builtin)
|
2021-02-28 00:20:04 +00:00
|
|
|
} else if let builtin @ Some(_) =
|
2021-06-13 03:54:16 +00:00
|
|
|
lit.suffix().and_then(|it| BuiltinInt::from_suffix(it))
|
2021-02-28 00:20:04 +00:00
|
|
|
{
|
2021-05-12 12:59:35 +00:00
|
|
|
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
|
2021-02-28 00:20:04 +00:00
|
|
|
} else {
|
2021-06-13 03:54:16 +00:00
|
|
|
let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(it));
|
2021-05-12 12:59:35 +00:00
|
|
|
Literal::Uint(lit.value().unwrap_or(0), builtin)
|
2020-11-06 21:52:22 +00:00
|
|
|
}
|
2020-04-01 10:37:51 +00:00
|
|
|
}
|
2020-11-06 21:52:22 +00:00
|
|
|
LiteralKind::FloatNumber(lit) => {
|
2021-06-13 03:54:16 +00:00
|
|
|
let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(it));
|
2020-11-06 21:52:22 +00:00
|
|
|
Literal::Float(Default::default(), ty)
|
2020-04-01 10:37:51 +00:00
|
|
|
}
|
2021-05-12 12:44:01 +00:00
|
|
|
LiteralKind::ByteString(bs) => {
|
|
|
|
let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
|
|
|
|
Literal::ByteString(text)
|
|
|
|
}
|
2020-11-06 21:52:22 +00:00
|
|
|
LiteralKind::String(_) => Literal::String(Default::default()),
|
2021-02-28 00:20:04 +00:00
|
|
|
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
|
2020-04-01 11:47:41 +00:00
|
|
|
LiteralKind::Bool(val) => Literal::Bool(val),
|
2020-04-01 10:37:51 +00:00
|
|
|
LiteralKind::Char => Literal::Char(Default::default()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|